package models

import (
	"errors"
	"strconv"

	"github.com/jinzhu/gorm"
)

// CustormerOrderSub 客户订单表
type CustormerOrderSub struct {
	gorm.Model
	Operator        string `gorm:"size:255"`
	Name            string
	Tel             string
	DeliveryAddress string
	OrderTrade      string
	OrderLine       string
	DeliveryTime    string
	Amount          float32
	Deposit         float32 // 定金
	Remarks         string
	State           string `gorm:"default:'未完成'"`
	Freight         float32
}

// CustormerGoodsSub 客户订单详细商品表
type CustormerGoodsSub struct {
	CustormerOrderID uint
	GoodsID          string
	Number           uint
	Unit             string
	CollectNum       uint
}

// CustormerGoodsSub 客户订单详细商品表
type CustormerComponentsSub struct {
	CustormerOrderID uint
	ComponentID      string
	Number           uint
}

// CreateCustormerOrderSub 创建客户订单
func CreateCustormerOrderSub(order *CustormerOrderSub, goods []CustormerGoodsSub) (*CustormerOrderInfoSub, error) {
	tx := db.Begin()

	err := tx.Table("custormer_order_subs").Create(order).Error
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	for _, v := range goods {
		v.CustormerOrderID = order.ID
		err = tx.Table("custormer_goods_subs").Create(&v).Error
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		commodity := GetCommodity(v.GoodsID)
		number := commodity.Number
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		var storeNumber uint
		if v.Unit == "箱" {
			storeNumber = v.Number * commodity.PackgeNum
		} else {
			storeNumber = v.Number
		}
		if number < storeNumber {
			tx.Rollback()
			return nil, errors.New("库存不足")
		}
		err = updateNumber(tx, v.GoodsID, number-storeNumber)
		if err != nil {
			tx.Rollback()
			return nil, err
		}
	}
	orderInfo, err := getCustormerOrderSub(tx, strconv.Itoa(int(order.ID)))
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()
	return orderInfo, nil
}

// CreateCustormerOrderNew 创建客户订单
func CreateCustormerOrderNew(order *CustormerOrderSub, goods []CustormerGoodsSub) (*CustormerOrderInfoSub, error) {
	tx := db.Begin()

	err := tx.Table("custormer_order_subs").Create(order).Error
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	for _, v := range goods {
		v.CustormerOrderID = order.ID
		err = tx.Table("custormer_goods_subs").Create(&v).Error
		if err != nil {
			tx.Rollback()
			return nil, err
		}
	}
	// 0，查出所有配件数量，commodity_components ，map结构：component_id，num
	components, _ := GetComponents()
	componentMap := Reset(components)
	// new add 创建客户订单的时候就可以直接报库存不足了
	for _, v := range goods {
		number, err := getNumber(tx, v.GoodsID)
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		//  加上配件新组合出来的成品

		// 1，拿出商品的配件比
		commodityComponents := []CommodityComponents{}
		_ = db.Table("custormer_components_subs").Where("commodity_id= ?", v.GoodsID).Find(&commodityComponents)
		// 2，计算下配件能组成几个成品
		flag := true            // 表示配件数量能不能凑成一个成品
		var collectNum uint = 0 //计数看能组成几个成品
		if commodityComponents != nil && len(commodityComponents) > 0 {
			for true {
				//这里面是一个商品配件的循环
				flag = JudgeComponentEnough(commodityComponents, componentMap)
				if !flag {
					break
				}
				// 如果商品配件的量管够，那就继续继续那件商品的配件
				collectNum++
			}
		}

		if number+collectNum < v.Number {
			tx.Rollback()
			return nil, errors.New("库存不足")
		}
		if collectNum == 0 {
			err = updateNumber(tx, v.GoodsID, number-v.Number)
			if err != nil {
				tx.Rollback()
				return nil, err
			}
		} else {
			componentMap = Reset(components)
			err = updateNumber(tx, v.GoodsID, 0)
			if err != nil {
				tx.Rollback()
				return nil, err
			}
			err = updateCollectNumSub(tx, order.ID, v.GoodsID, collectNum)
			if err != nil {
				tx.Rollback()
				return nil, err
			}
			//  如果配件组合新出来的成品加上已有的成品够卖的话，将减去的配件也记录到配件减去表中，方便后续如果取消这个订单的时候还原配件数量
			var i uint = 0
			custormerComponentMap := map[string]uint{}
			for true {
				if i < collectNum {
					for _, commodityComponent := range commodityComponents {
						custormerComponentMap[commodityComponent.ComponentID] = custormerComponentMap[commodityComponent.ComponentID] + commodityComponent.Number
						err = updateComponentNumber(tx, commodityComponent.ComponentID, componentMap[commodityComponent.ComponentID]-commodityComponent.Number)
						if err != nil {
							tx.Rollback()
							return nil, err
						}
						componentMap[commodityComponent.ComponentID] = componentMap[commodityComponent.ComponentID] - commodityComponent.Number

					}
				} else {
					break
				}
				i++
			}
			var custormerComponent CustormerComponentsSub
			for key, value := range custormerComponentMap {
				find := getCustormerComponentsSub(tx, order.ID, key, custormerComponent)
				if !find {
					err = UpdateCustormerComponentsSub(tx, order.ID, key, custormerComponent.Number+value)
					if err != nil {
						tx.Rollback()
						return nil, err
					}
				} else {
					err = CreateCustormerComponentsSub(tx, order.ID, key, value)
					if err != nil {
						tx.Rollback()
						return nil, err
					}
				}
			}

		}

	}

	orderInfo, err := getCustormerOrderSub(tx, strconv.Itoa(int(order.ID)))
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()
	return orderInfo, nil
}

func UpdateCustormerComponentsSub(tx *gorm.DB, orderID uint, componentID string, number uint) error {
	return tx.Table("custormer_components_subs").Where("custormer_order_id = ? and component_id = ?", orderID, componentID).Update("number", number).Error

}

func getCustormerComponentsSub(tx *gorm.DB, orderID uint, componentID string, custormerComponents CustormerComponentsSub) bool {
	return db.Table("custormer_components_subs").Where("custormer_order_id = ? and component_id = ?", orderID, componentID).Find(&custormerComponents).RecordNotFound()

}

func CreateCustormerComponentsSub(tx *gorm.DB, orderID uint, componentID string, number uint) error {
	custormerComponent := CustormerComponentsSub{
		CustormerOrderID: orderID,
		ComponentID:      componentID,
		Number:           number,
	}
	err := tx.Table("custormer_components_subs").Create(&custormerComponent).Error
	return err
}

// DeleteCustormerOrderSub 删除客户订单
func DeleteCustormerOrderSub(orderID string) error {
	ok, err := custormerOrderConfirmedSub(orderID)
	if err != nil {
		return err
	}
	if ok {
		return errors.New("已确认订单无法删除")
	}

	tx := db.Begin()

	var goods []CustormerGoodsSub
	err = tx.Table("custormer_goods_subs").Where("custormer_order_id = ?", orderID).Find(&goods).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	for _, v := range goods {
		if !HaveCommodity(v.GoodsID) {
			continue
		}
		commodity := GetCommodity(v.GoodsID)
		number := commodity.Number
		if err != nil {
			tx.Rollback()
			return err
		}
		var storeNumber uint
		if v.Unit == "箱" {
			storeNumber = commodity.PackgeNum * v.Number
		} else {
			storeNumber = v.Number
		}
		err = updateNumber(tx, v.GoodsID, number+storeNumber)
		if err != nil {
			tx.Rollback()
			return err
		}
	}

	err = tx.Table("custormer_goods_subs").Where(
		"custormer_order_id = ?", orderID).Delete(CustormerGoodsSub{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Table("custormer_order_subs").Unscoped().Where(
		"id = ?", orderID).Delete(CustormerOrderSub{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

// DeleteCustormerOrderNew 删除客户订单
func DeleteCustormerOrderNew(orderID string) error {
	ok, err := custormerOrderConfirmedSub(orderID)
	if err != nil {
		return err
	}
	if ok {
		return errors.New("已确认订单无法删除")
	}

	tx := db.Begin()

	var goods []CustormerGoodsSub
	err = tx.Table("custormer_goods_subs").Where("custormer_order_id = ?", orderID).Find(&goods).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	for _, v := range goods {
		if !HaveCommodity(v.GoodsID) {
			continue
		}
		// 删除客户订单的话就把库存回填回去
		number, err := getNumber(tx, v.GoodsID)
		if err != nil {
			tx.Rollback()
			return err
		}
		// 算一算从配件那边过来了几个成品
		var collectNum uint
		collectNum, err = getCollectNumSub(tx, orderID, v.GoodsID)
		if collectNum > 0 {
			err = updateNumber(tx, v.GoodsID, number+v.Number-collectNum)
			if err != nil {
				tx.Rollback()
				return err
			}
		} else {
			err = updateNumber(tx, v.GoodsID, number+v.Number)
			if err != nil {
				tx.Rollback()
				return err
			}
		}

		// 也要把配件数量还原
		custormerComponents := []CustormerComponentsSub{}
		_ = db.Table("custormer_components_subs").Where("custormer_order_id= ?", orderID).Find(&custormerComponents)
		if custormerComponents != nil && len(custormerComponents) > 0 {
			for _, custormerComponent := range custormerComponents {
				number, err := getComponentNumber(tx, custormerComponent.ComponentID)
				if err != nil {
					tx.Rollback()
					return err
				}
				err = updateComponentNumber(tx, custormerComponent.ComponentID, number+custormerComponent.Number)
				if err != nil {
					tx.Rollback()
					return err
				}
			}
			err = tx.Table("custormer_components_subs").Where(
				"custormer_order_id = ?", orderID).Delete(CustormerComponentsSub{}).Error
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	err = tx.Table("custormer_goods_subs").Where(
		"custormer_order_id = ?", orderID).Delete(CustormerGoodsSub{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Table("custormer_order_subs").Unscoped().Where(
		"id = ?", orderID).Delete(CustormerOrderSub{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

// ConfirmCustormerOrderSub 确认订单
func ConfirmCustormerOrderSub(orderID string, freight float32) (*CustormerOrderInfoSub, error) {
	ok, err := custormerOrderConfirmedSub(orderID)
	if err != nil {
		return nil, err
	}
	if ok {
		return nil, errors.New("订单请勿重复确认")
	}

	tx := db.Begin()

	err = tx.Table("custormer_order_subs").Where("id = ?", orderID).UpdateColumns(CustormerOrderSub{
		State:   "已完成",
		Freight: freight}).Error
	if err != nil {
		tx.Rollback()
		return nil, err
	}
	var goods []CustormerGoodsSub
	err = tx.Table("custormer_goods_subs").Where("custormer_order_id = ?", orderID).Find(&goods).Error
	if err != nil {
		tx.Rollback()
		return nil, err
	}
	// 更新下销量
	for _, v := range goods {
		commodity := GetCommodity(v.GoodsID)
		salesVolume := commodity.SalesVolume
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		var number uint
		if v.Unit == "箱" {
			number = v.Number * commodity.PackgeNum
		} else {
			number = v.Number
		}
		err = updateSalesVolume(tx, v.GoodsID, salesVolume+number)
		if err != nil {
			tx.Rollback()
			return nil, err
		}
	}
	orderInfo, err := getCustormerOrderSub(tx, orderID)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()
	return orderInfo, nil
}

// CustormerOrderInfoSub 与客户端通信的订单信息
type CustormerOrderInfoSub struct {
	CustormerOrderSub
	Goods []CommoditySale
}

// ListCustormerOrdersSub 获取所有客户订单
func ListCustormerOrdersSub() (orders []CustormerOrderInfoSub, err error) {
	err = db.Table("custormer_order_subs").Select(
		"id, created_at, operator, name, tel, delivery_address, delivery_time, amount, deposit, remarks, state, freight,order_line,order_trade").Find(&orders).Error
	if err != nil {
		return
	}

	for index, v := range orders {
		err = db.Raw(`select t2.id,t2.no, t2.name, t2.commodity_type type, t2.merchandise_safety_stock, t2.supply,t2.purchase_price, t1.number,t1.unit,t2.number stock_number  from custormer_goods_subs as t1 left outer join 
				commodities as t2 on t1.goods_id = t2.id where t1.custormer_order_id = ?`, v.ID).Scan(&orders[index].Goods).Error
		if err != nil {
			return
		}
	}
	return
}

func getCustormerOrderSub(tx *gorm.DB, orderID string) (*CustormerOrderInfoSub, error) {
	var order CustormerOrderInfoSub
	err := tx.Table("custormer_order_subs").Select(
		"id, created_at, operator, name, tel, delivery_address, delivery_time, amount, deposit, remarks, state, freight,order_line,order_trade").Where("id = ?", orderID).First(&order).Error
	if err != nil {
		return nil, err
	}
	err = tx.Raw(`select t2.id, t2.no, t2.name, t2.commodity_type type, t2.merchandise_safety_stock, t2.supply,t2.purchase_price, t1.number,t1.unit,t2.number stock_number  from custormer_goods_subs as t1 left outer join 
			commodities as t2 on t1.goods_id = t2.id where t1.custormer_order_id = ?`, orderID).Scan(&order.Goods).Error
	if err != nil {
		return nil, err
	}
	return &order, nil
}

func custormerOrderConfirmedSub(orderID string) (bool, error) {
	info := struct {
		State string `json:"state"`
	}{}
	err := db.Table("custormer_order_subs").Select("state").Where("id = ?", orderID).First(&info).Error
	if err != nil {
		return false, err
	}

	if info.State == "已完成" {
		return true, nil
	}

	return false, nil
}

func updateCollectNumSub(tx *gorm.DB, orderID uint, goodsID string, number uint) error {
	return tx.Table("custormer_goods_subs").Where("custormer_order_id = ? and goods_id = ?", orderID, goodsID).Update("collect_num", number).Error
}

func getCollectNumSub(tx *gorm.DB, orderID string, goodsID string) (number uint, err error) {
	info := struct {
		CollectNum uint
	}{}
	err = tx.Table("custormer_goods_subs").Select("collect_num").Where("custormer_order_id = ? and goods_id = ?", orderID, goodsID).Scan(&info).Error
	number = info.CollectNum
	return
}

// UpdateSaleOrder 更新订单客户信息
func UpdateSaleOrder(custormerOrderID string, custormerOrder *CustormerOrderSub) error {
	tx := db.Begin()

	err := tx.Table("custormer_order_subs").Where("id = ?", custormerOrderID).Updates(*custormerOrder).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil

}
